Introduction

Geomorph has several built-in functions to read landmark data files. Additionally, one can use standard IO functions in R to read in a text file. Geomorph also has the ability to digitize 2D or 3D data. For 3D, one can read in a 3D image in the form of a PLY file.

Read in Landmark Data from StereoMorph Files

Data files created using StereoMorph can be read into geomorph using the readShapes function in StereoMorph combined with the readland.shapes function in geomorph. The result is an geomorphShapes object which may be used in downstream GM analyses.



readland.shapes() (Expand for more details)

This function allows you to extract landmark coordinates from a “shapes,” file in your working environment. The possible arguments, or input values specified by the user, are below:

  • \(Shapes\): The “shapes” object that you wish to extract landmark coordinates from.
  • \(nCurvePts\): A single or multiple values that are used to determine the number of semilandmarks in each curve. So, inputing ‘c(20,50,10)’ returns three sets of curve points each with 20, 50, and 10 landmarks respectively.
  • \(continuous.curve\): One or a set of values used to indicate which curves (if any are present) are closed and whose same start and end point should be treated as a semilandmark.
  • \(scaled\):



library(StereoMorph)

myShapes <- readShapes("../Tutorials/Data-figures/Shapes") 
mydata <- readland.shapes(myShapes)
#plot lmks
mydata$landmarks$Fish1
##         [,1]      [,2]
## LM1 11.97986 -14.31232
## LM2 20.74027 -10.27158
## LM3 28.46039 -11.77180
## LM4 29.15027 -14.77224
## LM5 19.69997 -17.07185



Important Note!

Specimens with missing data can still be read using the procedure above. In these cases, the landmark values will be replaced with NA, and can be estimated in subsequent data-processing steps using estimate.missing.



Read Landmark Data from tps Files

TPS files have an inherent structure similar to the 3d-array data structure used in geomorph; whereas nts files correspond to a structure similar to two.d.arrays in geomorph. In both cases, data are read-in as a 3d-array. You can open tps files in a text editor to get familiar with their structure. To read a .tps file into geomorph, use the corresponding function: readland.tps

readland.tps()
  • \(file\): The file path to your tps coordinates.
  • \(specID\): An argument specifying whether specimen names should be extracted from the tps file. The default value is “None”, but the other options, “ID,” or “IMAGE,” will extract specimen names from either of those lines included in the tps file.
  • \(negNA\): A logical value (true or false) indicating whether negative landmark coordinates should be treated as missing values and replaced with ‘NA.’
  • \(readcurves\): Logical value specifying whether CURVE data should be read as semilandmarks.
  • \(warnmsg\): Logical value specifying whether warning messages should be printed.



tpsdata <- readland.tps("../Tutorials/Data-figures/salamanders.tps")
str(tpsdata)
dim(tpsdata)  
tpsdata[,,1]

tpsdata <- readland.tps("../Tutorials/Data-figures/salamanders.tps", specID="imageID") # Specify specimen labels
str(tpsdata)
tpsdata[,,1:2]



Important detail!

With .tps files, missing data may be coded by using negative numbers for the landmarks. In these cases, readland.tps will prompt the user to determine whether the negative values are actual landmark coordinates, or whether they represent missing data. In the latter case, the landmark values will be replaced with NA, and can be estimated in subsequent data-processing steps using estimate.missing.



Read Landmark Data from nts Files

ntsdata <- readland.nts("../Tutorials/Data-figures/RATS.nts")
str(ntsdata)
##  num [1:8, 1:2, 1:164] -0.45 -0.59 -0.515 -0.33 0 0.145 -0.045 -0.26 -0.475 -0.28 ...
ntsdata[,,1]
##        [,1]   [,2]
## [1,] -0.450 -0.475
## [2,] -0.590 -0.280
## [3,] -0.515 -0.120
## [4,] -0.330  0.000
## [5,]  0.000  0.000
## [6,]  0.145 -0.395
## [7,] -0.045 -0.420
## [8,] -0.260 -0.465



Read Landmark Data from Multiple tps or nts files

In some cases, landmark data for your specimens may be contained in separate tps or nts files that you want to read simultaneously. The functions readmulti.tps and readmulti.nts will allow you to do this:

mtpsdata <- readmulti.tps(c("../Tutorials/Data-figures/test1.tps", "../Tutorials/Data-figures/test2.tps"))
## 
## No specID provided; specimens will be numbered 1, 2, 3 ...
## 
## No curves detected; all points appear to be fixed landmarks.
## 
## No specID provided; specimens will be numbered 1, 2, 3 ...
## 
## No curves detected; all points appear to be fixed landmarks.
str(mtpsdata)
##  num [1:2, 1:2, 1:10] 119 316 136 151 126 ...
##  - attr(*, "dimnames")=List of 3
##   ..$ : NULL
##   ..$ : NULL
##   ..$ : chr [1:10] "1" "2" "3" "4" ...
mtpsdata[,,1]
##          [,1]     [,2]
## [1,] 119.1888 136.3207
## [2,] 315.6288 150.9804



Note that the list of file paths must be in vector format, that is, in the format of “c(”file1”, “file2”, etc)”

The same can be done with nts files as well:

mtpsdata <- readmulti.nts(c("../Tutorials/Data-figures/Pleth1.nts", 
                            "../Tutorials/Data-figures/Pleth2.nts", 
                            "../Tutorials/Data-figures/Pleth3.nts"))
str(mtpsdata)
##  num [1:12, 1:2, 1:3] 8.89 9.27 5.56 1.87 1.28 ...
##  - attr(*, "dimnames")=List of 3
##   ..$ : NULL
##   ..$ : NULL
##   ..$ : chr [1:3] "../Tutorials/Data-figures/Pleth1.nts_1" "../Tutorials/Data-figures/Pleth2.nts_1" "../Tutorials/Data-figures/Pleth3.nts_1"
mtpsdata[,,1]
##           [,1]     [,2]
##  [1,]  8.89372 53.77644
##  [2,]  9.26840 52.77072
##  [3,]  5.56104 54.21028
##  [4,]  1.87340 52.75100
##  [5,]  1.28180 53.18484
##  [6,]  1.24236 53.32288
##  [7,]  0.84796 54.70328
##  [8,]  3.35240 55.76816
##  [9,]  6.29068 55.70900
## [10,]  8.87400 55.25544
## [11,] 10.74740 55.43292
## [12,] 14.39560 52.75100



Read Landmark Data from Morphologika Files

Another file type that is sometimes encountered is a Morphologika file; developed for the Morphologika package. One can read these files using geomorph also, using the function read.morphologika:

morphdata <- read.morphologika("../Tutorials/Data-figures/mophologikaexample.txt")
str(morphdata)
## List of 4
##  $ coords   : num [1:31, 1:3, 1:15] 16 15 15 16.3 15.9 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : NULL
##   .. ..$ : NULL
##   .. ..$ : chr [1:15] "Specimen 1" "Specimen 2" "Specimen 3" "Specimen 4" ...
##  $ labels   : chr [1:15, 1] "Female" "Female" "Female" "Female" ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:15] "Specimen 1" "Specimen 2" "Specimen 3" "Specimen 4" ...
##   .. ..$ : chr "Sex"
##  $ wireframe: num [1:40, 1:2] 1 22 6 24 15 15 17 15 5 23 ...
##  $ polygon  : num [1:37, 1:3] 7 8 9 9 6 11 10 11 13 12 ...
dim(morphdata$coords)
## [1] 31  3 15
morphdata$coords[,,1]
##        [,1]  [,2]  [,3]
##  [1,] 16.01 24.17 11.18
##  [2,] 15.00 24.86 11.16
##  [3,] 14.96 25.54 11.52
##  [4,] 16.26 24.36 11.48
##  [5,] 15.89 26.61 11.83
##  [6,] 17.16 25.33 12.35
##  [7,] 18.22 23.65 11.12
##  [8,] 18.77 23.75 11.21
##  [9,] 18.72 24.24 11.62
## [10,] 19.26 25.71 10.33
## [11,] 18.21 25.39 12.05
## [12,] 19.32 25.91 14.39
## [13,] 17.45 26.36 13.70
## [14,] 14.51 26.93 11.50
## [15,] 15.93 26.94 12.36
## [16,] 17.11 26.94 13.63
## [17,] 18.69 26.98 14.67
## [18,] 19.50 27.03 15.03
## [19,] 15.75 29.67 10.89
## [20,] 14.96 29.08 11.07
## [21,] 14.92 28.36 11.48
## [22,] 15.85 29.43 11.37
## [23,] 15.93 27.16 12.02
## [24,] 17.07 28.57 12.32
## [25,] 17.90 30.15 11.26
## [26,] 18.62 30.00 11.18
## [27,] 18.69 29.71 11.45
## [28,] 19.14 28.53 10.28
## [29,] 18.17 28.51 12.08
## [30,] 19.25 28.15 14.23
## [31,] 17.48 27.52 13.71



Read 3D image (PLY file)

Sometimes, we may wish to digitize directly from 3D images. These come in the form of ply files, and geomorph has the ability to read, and then digitize such images.

mandible <- read.ply("../data/Mandible.ply", ShowSpecimen = TRUE)
rgl.bg(color = c("#ceecf0"))
rglwidget()
                                            (Click and drag to manipulate)



Read in text file (for landmarks or other variables)

One may have additional data, covariates, or other specimen information that one wishes to read into R for downstream analyses. As we are working in the R environment, one is free to do so using a variety of read functions. Below we provide an example for a data matrix, and a phylogeny:

Salamanders <- read.csv("../data/salamanders.csv", header=FALSE)
library(ape)
tree <- read.tree("../data/plethtree.tre")
plot(tree)



Converting a matrix of landmark coordinates into a 3D Array

Most analytical functions in geomorph require one’s data be in 3D array (nxpxk) format. The functions discussed above return data in array format automatically as part of the read-in process. However, if your raw data are not in tps, nts, or morphologika format, the arrayspecs function can be used to convert them into a 3D array:

mydata <- arrayspecs(as.matrix(Salamanders), 12, 2)
str(mydata)
##  int [1:12, 1:2, 1:287] 448 472 266 110 97 92 56 158 306 453 ...



Important Note!

Make certain that the number of landmarks (the p argument) is correct! If the incorrect value is input, but that value is still divisible by the number of dimensions (k), the function will still run. This will result in an array with the incorrect number of specimens, each with the incorrect number of landmarks.